package com.shenma2009.log;

import com.alibaba.fastjson2.JSON;
import com.shenma2009.domain.ResultResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author 军哥
 * @version 1.0
 * @description: SmLogAspect
 * @date 2023/6/7 9:01
 */

@Aspect
@Component
public class SmLogAspect {

    @Pointcut("@annotation(com.shenma2009.log.SmLog)")
    public void smLogPointCut() {}

    /**
     * @description 后置通知
     * @author 军哥
     * @date 2023/6/7 9:12
     * @version 1.0
     */
    @AfterReturning(value = "smLogPointCut()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue){

        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取方法名
        String methodName = signature.getName();
        // 获取参数
        List<Object> args = Arrays.asList(point.getArgs());

        Method method = signature.getMethod();
        SmLog annotation = method.getAnnotation(SmLog.class);
        System.out.println("后置通知 => value:"+annotation.value());
        System.out.println("后置通知 => level:"+annotation.level());

        System.out.println("后置通知 => 方法为：" + methodName + ",参数为：" + JSON.toJSONString(args) + ",返回值为：" + JSON.toJSONString(returnValue));
    }

    /**
     * @description 前置通知
     * @author 军哥
     * @date 2023/6/7 15:17
     * @version 1.0
     */
    @Before(value = "execution(* com.shenma2009.controller.IndexController.insertSmLog(..))")
    public void doBefore(JoinPoint point) throws Exception {
        MethodSignature signature = (MethodSignature) point.getSignature();

        // 获取注解信息
        Method method = signature.getMethod();
        SmLog annotation = method.getAnnotation(SmLog.class);
        System.out.println("前置通知 => value:"+annotation.value());
        System.out.println("前置通知 => level:"+annotation.level());

        // 检查权限
        if(!annotation.value().equals("insert")) {
            throw new Exception("权限不足");
        }
        System.out.println("前置通知 => 权限合法");
    }

    /**
     * @description 环绕通知
     * @author 军哥
     * @date 2023/6/7 14:53
     * @version 1.0
     */

    // 第一种方式
    @Around("@annotation(com.shenma2009.log.SmLog)")
    // 第二种表达式
    //@Around(value = "smLogPointCut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        //获取方法参数
        Object[] args = point.getArgs();
        System.out.println("环绕通知 => 参数为：" + JSON.toJSONString(args));

        ResultResponse ret = (ResultResponse) point.proceed();
        if(ret.getCode() == 200){
            //code=1，说明操纵成功
            System.out.println("环绕通知 => 操纵成功");
            return ret;
        }
        //操作失败返回Result的执行结果
        System.out.println("环绕通知 => 操纵失败");
        return ret;
    }

    //设置抛出异常后通知获取原始方法运行时抛出的异常对象，要求throwing属性值必须与方法形参名相同
    @AfterThrowing(value = "smLogPointCut()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println("异常通知 => "+JSON.toJSONString(t));
    }
}
